package command

import (
	"fmt"
)

const slotnums = 7

type Command interface {
	execute()
}

/////////////////////////////////////
type RemoteControl struct {
	onCommands  []Command
	offCommands []Command
}

func NewRemoteControl() *RemoteControl {
	r := new(RemoteControl)
	r.onCommands = make([]Command, slotnums, slotnums)
	r.offCommands = make([]Command, slotnums, slotnums)

	return r
}

func (c *RemoteControl) SetCommand(s uint, on Command, off Command) {
	if s >= slotnums {
		return
	}

	c.onCommands[s] = on
	c.offCommands[s] = off
}

func (c *RemoteControl) OnButtonWasPushed(s uint) {
	if s >= slotnums {
		return
	}

	c.onCommands[s].execute()
}

func (c *RemoteControl) OffButtonWasPushed(s uint) {
	if s >= slotnums {
		return
	}

	c.offCommands[s].execute()
}

/////////////////////////////////////
type Light struct {
}

func (c *Light) on() {
	fmt.Println("light is on!")
}

func (c *Light) off() {
	fmt.Println("light is off!")
}

type Stereo struct {
}

func (c *Stereo) on() {
	fmt.Println("stereo is on!")
}

func (c *Stereo) off() {
	fmt.Println("stereo is off!")
}

func (c *Stereo) setCd() {
	fmt.Println("stereo set cd!")
}

func (c *Stereo) setDvd() {
	fmt.Println("stereo set dvd!")
}

func (c *Stereo) setRadio() {
	fmt.Println("stereo set radio!")
}

func (c *Stereo) setVolume() {
	fmt.Println("stereo set volume!")
}

type GarageDoor struct {
}

func (c *GarageDoor) up() {
	fmt.Println("garage door is up!")
}

func (c *GarageDoor) down() {
	fmt.Println("garage door is down!")
}

func (c *GarageDoor) stop() {
	fmt.Println("garage door is stopped!")
}

func (c *GarageDoor) lightOn() {
	fmt.Println("garage door light is on!")
}

func (c *GarageDoor) lightOff() {
	fmt.Println("garage door light is off!")
}

/////////////////////////////////////
type LightOnCommand struct {
	light *Light
}

func NewLightOnCommand(l *Light) *LightOnCommand {
	r := new(LightOnCommand)
	r.light = l

	return r
}

func (c *LightOnCommand) execute() {
	c.light.on()
}

type LightOffCommand struct {
	light *Light
}

func NewLightOffCommand(l *Light) *LightOffCommand {
	r := new(LightOffCommand)
	r.light = l

	return r
}

func (c *LightOffCommand) execute() {
	c.light.off()
}

type StereoOnWithCDCommand struct {
	stereo *Stereo
}

func NewStereoOnWithCDCommand(s *Stereo) *StereoOnWithCDCommand {
	r := new(StereoOnWithCDCommand)
	r.stereo = s

	return r
}

func (c *StereoOnWithCDCommand) execute() {
	c.stereo.on()
	c.stereo.setCd()
	c.stereo.setVolume()
}

type StereoOffCommand struct {
	stereo *Stereo
}

func NewStereoOffCommand(s *Stereo) *StereoOffCommand {
	r := new(StereoOffCommand)
	r.stereo = s

	return r
}

func (c *StereoOffCommand) execute() {
	c.stereo.off()
}

type GarageDoorDownCommand struct {
	garage *GarageDoor
}

func NewGarageDoorDownCommand(g *GarageDoor) *GarageDoorDownCommand {
	r := new(GarageDoorDownCommand)
	r.garage = g

	return r
}

func (c *GarageDoorDownCommand) execute() {
	c.garage.down()
}

type GarageDoorUpCommand struct {
	garage *GarageDoor
}

func NewGarageDoorUpCommand(g *GarageDoor) *GarageDoorUpCommand {
	r := new(GarageDoorUpCommand)
	r.garage = g

	return r
}

func (c *GarageDoorUpCommand) execute() {
	c.garage.up()
}
